using UnityEngine;
using UnityEditor.Animations;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using System.Linq;
using DanMuHelper.Tools;

[DisallowMultipleComponent]
[RequireComponent(typeof(Animation))]
public class RecordTransformHierarchy : MonoBehaviour
{
    [FolderPath]
    [Header("动画录制根目录定义")]
    public string SampleAnimationSaveFolerPath = "Assets/Art/Animation/Recordings/";

    [Header("动画片段文件夹名称")]
    public string FolderName;

    [Header("间隔帧")]
    public int IntervalFrame = 4;

    [Header("爆炸力度")]
    public float explodeForce = 8;

    [Header("爆炸范围")]
    public float explodeRaids = 5;

    [Header("爆炸点")]
    public Transform explodePos;

    [Header("物理失效时间")]
    public float PhysicsDevitalizedTime = 2.5f;

    [Header("录制保存的动画片段")]
    public AnimationClip clip;

    [Header("爆炸组Transfrom")]
    public Transform BombGroupTranform;

    private float PhysicsDevitalizedTimer;

    private GameObjectRecorder m_Recorder;

    private List<Rigidbody> rigidbodies = new List<Rigidbody>();

    private List<Collider> colliders = new List<Collider>();

    private bool isStartRecording;

    private bool isPhysicsDevitalizedFlag;

    private void OnValidate()
    {
        if (explodePos == null)
            explodePos = transform.root;

        if (string.IsNullOrEmpty(FolderName))
        {
            if (transform.root != null) FolderName = transform.root.name;
            else FolderName = transform.name;
        }

        if (BombGroupTranform == null)
            BombGroupTranform = transform;
    }

    private void Awake()
    {
        for (int i = 0; i < BombGroupTranform.childCount; i++)
        {
            if (!BombGroupTranform.GetChild(i).TryGetComponent(out Collider collder))
                collder = BombGroupTranform.GetChild(i).GetOrAddComponent<MeshCollider>();

            if (collder.GetType() == typeof(MeshCollider))
                ((MeshCollider)collder).convex = true;
            Rigidbody rigidbody = BombGroupTranform.GetChild(i).GetOrAddComponent<Rigidbody>();
            rigidbody.isKinematic = true;
            rigidbody.useGravity = false;
            rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
            SetDensity(rigidbody);
        }

        rigidbodies = GetComponentsInChildren<Rigidbody>().ToList();
        colliders = GetComponentsInChildren<Collider>().ToList();
    }

    private void Start()
    {
        // Create recorder and record the script GameObject.
        m_Recorder = new GameObjectRecorder(gameObject);

        // Bind all the Transforms on the GameObject and all its children.
        m_Recorder.BindComponentsOfType<Transform>(gameObject, true);
    }

    private void LateUpdate()
    {
        if (clip == null || !isStartRecording)
            return;

        if (!isPhysicsDevitalizedFlag)
        {
            PhysicsDevitalizedTimer -= Time.deltaTime;

            if (PhysicsDevitalizedTimer <= 0)
            {
                isPhysicsDevitalizedFlag = true;
                for (int i = 0; i < rigidbodies.Count; i++)
                {
                    colliders[i].isTrigger = true;
                }
            }
        }

        float frame = IntervalFrame;
        if (Time.frameCount % frame == 0)
        {
            m_Recorder.TakeSnapshot(Time.deltaTime);
        }
    }

    private void OnDisable()
    {
        if (clip == null)
            return;

        if (m_Recorder.isRecording)
            m_Recorder.SaveToClip(clip);
    }

    private void SetDensity(Rigidbody rigid, float density = 3)
    {
        rigid.SetDensity(density);
        float mass = rigid.mass;
        if (mass < 0.1f)
            mass = 0.1f;
        if (mass > 400)
            mass = 400;
        rigid.mass = mass;
    }

    private void BombCreat()
    {
        for (int i = 0; i < rigidbodies.Count; i++)
        {
            rigidbodies[i].useGravity = true;
            rigidbodies[i].isKinematic = false;
            rigidbodies[i].AddExplosionForce(explodeForce, explodePos.position, explodeRaids);
        }
    }

    [Button("开始动画录制", ButtonSizes.Large)]
    [ButtonGroup("动画录制")]
    public void StartRecording()
    {
        if (!isStartRecording)
        {
            PhysicsDevitalizedTimer = PhysicsDevitalizedTime;
            isStartRecording = true;
            BombCreat();
        }
    }

    [Button("关闭动画录制", ButtonSizes.Large)]
    [ButtonGroup("动画录制")]
    public void CloseRecording()
    {
        if (isStartRecording)
        {
            isStartRecording = false;
            if (m_Recorder.isRecording)
                m_Recorder.SaveToClip(clip);

            Time.timeScale = 0;
        }
    }

    [Button]
    public void PlayAnimation()
    {
        if (TryGetComponent(out Animation animation))
        {
            float frame = IntervalFrame;
            float speed = 1 / frame;
            foreach (AnimationState item in animation)
            {
                item.speed = speed;
            }
            animation.Play();
        }
    }

    //[Button("清除此次录制动画")]
    //public void ResetRecordingAnimation()
    //{
    //    isStartRecording = false;
    //    m_Recorder.ResetRecording();
    //}

    [Button("创建动画文件")]
    public void CreatAnimationClipFile()
    {
        //判断根目录是否存在
        if (!Directory.Exists(SampleAnimationSaveFolerPath))
            Directory.CreateDirectory(SampleAnimationSaveFolerPath);

        //判断上级文件夹是否存在
        string ownerFolderPath = SampleAnimationSaveFolerPath + "/" + FolderName;
        if (!Directory.Exists(ownerFolderPath))
            Directory.CreateDirectory(ownerFolderPath);

        //判断动画文件是否存在
        string clipPath = ownerFolderPath + "/" + transform.name + ".anim";
        if (File.Exists(clipPath)) return;

        AnimationClip animationClip = new AnimationClip
        {
            legacy = true,
        };
        clip = animationClip;

        if (!gameObject.TryGetComponent(out Animation animation))
            animation = gameObject.AddComponent<Animation>();
        animation.clip = clip;
        animation.AddClip(clip, clip.name);
        animation.playAutomatically = false;
        animation.cullingType = AnimationCullingType.BasedOnRenderers;
        AssetDatabase.CreateAsset(animationClip, clipPath);
        AssetDatabase.SaveAssets();
    }

    [Button("删除动画文件")]
    public void DeleteClipFile()
    {
        if (clip != null)
        {
            if (gameObject.TryGetComponent(out Animation animation))
                animation.RemoveClip(clip);

            string ownerFolderPath = SampleAnimationSaveFolerPath + "/" + FolderName;
            string clipPath = ownerFolderPath + "/" + transform.name + ".anim";
            AssetDatabase.DeleteAsset(clipPath);
            AssetDatabase.SaveAssets();
        }
    }
}